package http

import (
	"fmt"
	"gitee.com/saxon134/go-utils/saData"
	"gitee.com/saxon134/go-utils/saData/saError"
	"gitee.com/saxon134/go-utils/saData/saHit"
	"gitee.com/saxon134/go-utils/saLog"
	"gitee.com/saxon134/workflow/api"
	"github.com/gin-gonic/gin"
	"runtime"
	"strings"
)

// Res 返回正确时数据
func Res(c *api.Context, v *api.Response) {
	if c != nil {
		if v == nil {
			v = new(api.Response)
		}

		var dic = map[string]interface{}{"code": 0}
		if v.Result != nil {
			dic["result"] = v.Result
		}

		if v.Ext != nil {
			dic["ext"] = v.Ext
		}

		if c.Paging.Valid == true {
			v.Total = saHit.Int64(v.Total > 0, v.Total, c.Paging.Total)
			v.Total = saHit.Int64(v.Total > 0, v.Total, int64(c.Paging.Offset+c.Paging.Limit))
			dic["hasNext"] = v.Total > int64(c.Paging.Offset+c.Paging.Limit)
			dic["totalCount"] = v.Total
		}

		if gc, ok := c.Context.(*gin.Context); ok {
			gc.JSON(200, dic)
			gc.Abort()
		}
	}
}

// ResErr 返回error
func ResErr(c *api.Context, err interface{}) {
	if c == nil {
		return
	}

	// gin context
	gc, _ := c.Context.(*gin.Context)

	var msg = "接口报错"
	var code = saError.SensitiveErrorCode
	var caller = ""
	var needCaller = false

	if s, ok := err.(string); ok {
		needCaller = true
		code = saError.NormalErrorCode
		if s != "" {
			msg = s
		}
	} else if e, ok := err.(saError.Error); ok {
		code = e.Code
		msg = e.Msg
		caller = e.Caller
	} else if e, ok := err.(*saError.Error); ok {
		code = e.Code
		msg = e.Msg
		caller = e.Caller
	} else if e, ok := err.(error); ok {
		needCaller = true
		err_s := e.Error()
		var dic map[string]interface{}
		_ = saData.StrToModel(err_s, &dic)

		//判断是否是micro error
		id, _ := saData.ToStr(dic["id"])
		if id == "go.micro.client" {
			err_s, _ = saData.ToStr(dic["detail"])
		}

		//如果是saError，则错误码、信息按saError输出；否则全部按照敏感信息处理
		sa_err := new(saError.Error)
		if saData.StrToModel(err_s, sa_err) == nil && sa_err.Code > 0 {
			code = sa_err.Code
			msg = sa_err.Msg
			caller = sa_err.Caller
		} else {
			code = saError.SensitiveErrorCode
			msg = err_s
		}
	}

	//获取调用栈
	if needCaller || caller == "" {
		pc := make([]uintptr, 10)
		n := runtime.Callers(2, pc)
		for i := 0; i < n; i++ {
			if needCaller && i >= 1 {
				break
			}
			if caller == "" && i >= 10 {
				break
			}

			f := runtime.FuncForPC(pc[i])
			file, line := f.FileLine(pc[i])
			if strings.Contains(file, "go/pkg/mod") ||
				strings.Contains(file, "techio/http/http.go") ||
				strings.Contains(file, "techio/http/middleware") {
				continue
			}
			caller += fmt.Sprintf("%s:%d\n", file, line)
		}
	}

	//请求日志
	errLog := fmt.Sprintf("\n[ERR] %s %s %d", gc.Request.Method, gc.Request.URL.Path, code)
	errLog += "\n[MSG] " + msg
	{
		errLog += "\n[HEA] " +
			"AppKey:" + gc.GetHeader("AppKey") + " " +
			"Product:" + gc.GetHeader("Product") + " " +
			"Scene:" + gc.GetHeader("Scene") + " " +
			"Remoteip:" + gc.GetHeader("RemoteIp")
		if gc.Request.URL.RawQuery != "" {
			errLog += "\n[QUE] " + gc.Request.URL.RawQuery
		}

		if gc.Request.Method == "POST" {
			s := ""
			tp := gc.Request.Header.Get("Content-Type")
			tp = saHit.Str(tp == "", gc.Request.Header.Get("content-type"), tp)

			if tp == "application/json" {
				s = saData.String(c.RawParam)
			} else {
				s = saData.String(gc.Request.PostForm)
			}
			if s != "" {
				errLog += "\n[BOD] " + s
			}
		}
	}
	errLog += strings.TrimSuffix("\n"+caller, "\n")
	saLog.Err(errLog)

	if code != 0 {
		rsp_v := map[string]interface{}{"code": code}
		rsp_v["msg"] = msg

		gc.JSON(400, rsp_v)
		gc.Abort()
		return
	}

	//异常情况
	gc.JSON(500, &map[string]interface{}{"code": saError.NormalErrorCode, "msg": "服务器开了个小差"})
	gc.Abort()
}
